/**
 * 规范化类名输入，支持字符串、数组和对象类型。
 * 该函数会根据输入值的类型调用不同的处理函数，将输入转换为一个规范化的类名字符串。
 * 对于字符串，直接返回；对于数组，会递归处理其中的每个元素；对于对象，会根据对象的值决定是否添加对应的键作为类名。
 * 
 * @param {string|Array|Object} propsClass - 待规范化的类名。可以是字符串、数组或对象。
 * @returns {string} 规范化后的类名字符串，多个类名之间用空格分隔。如果输入不符合预期，返回空字符串。
 */
function normalizeClass(propsClass) {
  if (typeof propsClass === 'string') {
    return propsClass;
  }
  if (Array.isArray(propsClass)) {
    return normalizeArray(propsClass);
  }
  if (typeof propsClass === 'object' && propsClass !== null) {
    return normalizeObject(propsClass);
  }
  return '';
}

/**
 * 规范化类名数组。
 * 该函数会遍历数组中的每个元素，递归调用 `normalizeClass` 函数对元素进行处理，
 * 过滤掉处理结果为空的元素，最后将剩余的类名用空格连接成一个字符串。
 * 
 * @param {Array} arr - 待规范化的类名数组，数组元素可以是字符串、数组或对象。
 * @returns {string} 规范化后的类名字符串，多个类名之间用空格分隔。
 */
function normalizeArray(arr) {
  return arr
    .map((item) => normalizeClass(item))
    .filter((item) => item)
    .join(' ');
}

/**
 * 规范化类名对象。
 * 该函数会遍历对象的键值对，根据值的类型决定是否将对应的键作为类名添加到结果中。
 * 如果值是布尔值，只有为 `true` 时才添加；如果值是数组或对象，会递归调用 `normalizeClass` 函数判断是否添加；
 * 对于其他类型的值，只要值为真值就添加。最后将符合条件的键用空格连接成一个字符串。
 * 
 * @param {Object} obj - 待规范化的类名对象，键为类名，值决定该类名是否被添加。
 * @returns {string} 规范化后的类名字符串，多个类名之间用空格分隔。
 */
function normalizeObject(obj) {
  return Object.entries(obj)
    .filter(([_, value]) => {
      if (typeof value === 'boolean') {
        return value;
      }
      if (Array.isArray(value) || typeof value === 'object') {
        return !!normalizeClass(value);
      }
      return !!value;
    })
    .map(([key]) => key)
    .join(' ');
}

